package me.gacl.websocket.JSR356.example;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import me.gacl.websocket.Const;
import me.gacl.websocket.wsmessages.StringWebsocketMessage;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket处理类, 使用J2EE7的标准
 * @ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 * Created by 孤傲苍狼 on 2016/2/18.
 */
@ServerEndpoint("/websocket/{clientName}")
public class WebSocketServerEndPoint {

    /**
     * 打开连接时触发
     * @param session
     */
    @OnOpen
    public void onOpen(Session session ,@PathParam(value = "clientName") String clientName){
        //每当有一个新的WebSocket客户端连接上来时,就会产生一个Session,Session的Id为一个数字,从0开始
        String sessionId = session.getId();
        System.out.println("WebSocket客户端的SessionId为:"+ sessionId);
        System.out.println("WebSocket客户端的名称为:"+clientName);
        //将连接上来的客户端保存起来，然后返回一个clientId作为该客户端的唯一标识
        String clientId = SessionUtils.put(clientName, session);
        //构建需要发送的系统消息
        StringWebsocketMessage stringWebsocketMessage = new StringWebsocketMessage();
        JSONObject message = new JSONObject();
        message.put("messageText","WebSocket连接成功");
        JSONObject messageData = new JSONObject();
        messageData.put("clientId",clientId);
        messageData.put("sessionId",sessionId);
        message.put("messageData",messageData);
        stringWebsocketMessage.setMessage(message);
        stringWebsocketMessage.setMessageType(Const.StringWebsocketMessageType.SYS_MESSAGE);
        session.getAsyncRemote().sendText(JSON.toJSONString(stringWebsocketMessage));
    }

    /**
     * 收到客户端消息时触发
     * @param message
     * @return
     */
    @OnMessage
    public void onMessage(String message) {
        System.out.println("接收到的消息："+message);
        //将接收到的消息转成一个JSON对象
        JSONObject StringWebsocketMessage = JSON.parseObject(message);
        String messageType = StringWebsocketMessage.getString("messageType");
        JSONObject messageData = StringWebsocketMessage.getJSONObject("message");
        if (Const.StringWebsocketMessageType.TEXT_MESSAGE.equalsIgnoreCase(messageType)){
            //发送接收到的消息到所有WebSocket客户端
            sendMessageToAllClient(message);
        }else if(Const.StringWebsocketMessageType.ACTION_MESSAGE.equalsIgnoreCase(StringWebsocketMessage.getString("messageType"))){
            String messageText=messageData.getString("messageText");
            if (messageText.equalsIgnoreCase("closeWebSocket")){
                JSONObject param = messageData.getJSONObject("param");
                JSONArray webSocketClientArr = param.getJSONArray("webSocketClientArr");
                int len = webSocketClientArr.size();
                for(int i=0;i<len;i++){
                    JSONObject webSocketClient = webSocketClientArr.getJSONObject(i);
                    String clientId = webSocketClient.getString("clientId");
                    try {
                        SessionUtils.get(clientId).close();
                        SessionUtils.remove(clientId);
                        System.out.println("SessionUtils.clients.size()="+SessionUtils.clients.size());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }else if(messageText.equalsIgnoreCase("userLogin")){
                JSONObject param = messageData.getJSONObject("param");
                String userName = param.getString("userName");
                String password = param.getString("password");
                boolean validateResult = BusInessService.validateUser(userName,password);
                //组装需要发送的通知消息
                StringWebsocketMessage stringWebsocketMessage = new StringWebsocketMessage();
                stringWebsocketMessage.setMessageType(Const.StringWebsocketMessageType.ACTION_MESSAGE);
                JSONObject responseMessage = new JSONObject();
                responseMessage.put("action","userLogin");
                if (validateResult){
                    responseMessage.put("messageText","用户名和密码正确登录成功");
                    JSONObject paramObj = new JSONObject();
                    paramObj.put("success",true);
                    paramObj.put("success",true);
                    responseMessage.put("param",paramObj);
                }else{
                    responseMessage.put("messageText","用户名或密码错误,登录失败");
                    JSONObject paramObj = new JSONObject();
                    paramObj.put("success",false);
                    responseMessage.put("param",paramObj);
                }
                stringWebsocketMessage.setMessage(responseMessage);
                Map<String, Session> mapAcceptDataWebSocketClient =getAcceptDataWebSocketClients("userLogin");
                //发送消息到目标webSocket客户端集合
                sendMessageToTargetClient(JSON.toJSONString(stringWebsocketMessage), mapAcceptDataWebSocketClient);
                return;
            }else if(messageText.equalsIgnoreCase("inputText")){
                JSONObject param = messageData.getJSONObject("param");
                String inputText = param.getString("inputText");
                String controlId = param.getString("controlId");
                //发消息的WebSocket客户端
                String fromWebSocketClientId = param.getString("fromWebSocketClientId");
                //组装需要发送的通知消息
                StringWebsocketMessage stringWebsocketMessage = new StringWebsocketMessage();
                stringWebsocketMessage.setMessageType(Const.StringWebsocketMessageType.ACTION_MESSAGE);
                JSONObject responseMessage = new JSONObject();
                responseMessage.put("action","inputText");
                JSONObject paramObj = new JSONObject();
                paramObj.put("inputText",inputText);
                paramObj.put("controlId",controlId);
                paramObj.put("fromWebSocketClientId",fromWebSocketClientId);
                responseMessage.put("param",paramObj);
                stringWebsocketMessage.setMessage(responseMessage);
                Map<String, Session> mapAcceptDataWebSocketClient =getAcceptDataWebSocketClients("userLogin");
                //发送消息到目标webSocket客户端集合
                sendMessageToTargetClient(JSON.toJSONString(stringWebsocketMessage), mapAcceptDataWebSocketClient);
                return;
            }
            //接收推送数据的目标webSocket客户端集合
            Map<String, Session> mapAcceptDataWebSocketClient = getAcceptDataWebSocketClients();
            //发送消息到目标webSocket客户端集合
            sendMessageToTargetClient(message, mapAcceptDataWebSocketClient);
        }else if(Const.StringWebsocketMessageType.NOTICE_MESSAGE.equalsIgnoreCase(StringWebsocketMessage.getString("messageType"))){
            //TODO 推送通知消息到指定客户端
            JSONObject param = messageData.getJSONObject("param");
            String messageText = messageData.getString("messageText");
            JSONArray targetClientArr = param.getJSONArray("targetClientArr");
            int len = targetClientArr.size();
            Map<String, Session> mapAcceptDataWebSocketClient = new HashMap<String, Session>();
            String messageContent="";
            for(int i=0;i<len;i++){
                JSONObject jsonObject = targetClientArr.getJSONObject(i);
                String clientId = jsonObject.getString("clientId");
                Session session = SessionUtils.get(clientId);
                mapAcceptDataWebSocketClient.put(clientId,session);
                messageContent+=clientId+"、";
            }
            if(messageContent.length()>0){
                messageContent=messageContent.substring(0,messageContent.length()-1);
            }
            messageContent+="用户:"+messageText;
            //组装需要发送的通知消息
            StringWebsocketMessage stringWebsocketMessage = new StringWebsocketMessage();
            stringWebsocketMessage.setMessageType(Const.StringWebsocketMessageType.NOTICE_MESSAGE);
            stringWebsocketMessage.setMessage("此聊天内容来自系统通知消息："+messageContent);
            //发送消息到目标webSocket客户端集合
            sendMessageToTargetClient(JSON.toJSONString(stringWebsocketMessage), mapAcceptDataWebSocketClient);
        }

    }

    private Map<String, Session> getAcceptDataWebSocketClients() {
        //接收推送数据的目标webSocket客户端集合
        Map<String, Session> mapAcceptDataWebSocketClient = new HashMap<String, Session>();
        //SessionUtils.clients保存了所有连接上来的WebSocket客户端
        Map<String, Session> clients = SessionUtils.clients;
        //从clients集合中找出需要接收推送数据的webSocket目标客户端
        for (Map.Entry<String, Session> entry : clients.entrySet()) {
            String clientId = entry.getKey();
            Session webSocketClientSession = entry.getValue();
            String clientName = clientId.split("\\_")[0];
            if (clientName.equals("webSocketClientList")) {
                if (!mapAcceptDataWebSocketClient.containsKey(clientId)) {
                    //将需要接受推送数据的WebSocketClient对应的Session添加到map中
                    mapAcceptDataWebSocketClient.put(clientId, webSocketClientSession);
                }
            }
        }

        return mapAcceptDataWebSocketClient;
    }

    /**
     * 获取接受消息的目标客户端
     * @param targetClientName 目标客户端名称
     * @return mapAcceptDataWebSocketClient 接收推送数据的目标webSocket客户端集合
     */
    private Map<String, Session> getAcceptDataWebSocketClients(String targetClientName) {
        //接收推送数据的目标webSocket客户端集合
        Map<String, Session> mapAcceptDataWebSocketClient = new HashMap<String, Session>();
        //SessionUtils.clients保存了所有连接上来的WebSocket客户端
        Map<String, Session> clients = SessionUtils.clients;
        //从clients集合中找出需要接收推送数据的webSocket目标客户端
        for (Map.Entry<String, Session> entry : clients.entrySet()) {
            String clientId = entry.getKey();
            Session webSocketClientSession = entry.getValue();
            String clientName = clientId.split("\\_")[0];
            if (clientName.equals(targetClientName)) {
                if (!mapAcceptDataWebSocketClient.containsKey(clientId)) {
                    //将需要接受推送数据的WebSocketClient对应的Session添加到map中
                    mapAcceptDataWebSocketClient.put(clientId, webSocketClientSession);
                }
            }
        }

        return mapAcceptDataWebSocketClient;
    }

    /**
     * 异常时触发
     * @param session
     */
    @OnError
    public void onError(Throwable throwable,
                        Session session,
                        @PathParam(value = "clientName") String clientName) {
        throwable.printStackTrace();
        session.getAsyncRemote().sendText("sessionId为"+session.getId()+"WebSocket连接出错，原因是："+throwable.getMessage());
        SessionUtils.remove(clientName,session);
    }

    /**
     * 关闭连接时触发
     * @param session
     */
    @OnClose
    public void onClose(Session session,CloseReason closeReason,
                        @PathParam(value = "clientName") String clientName) {
        System.out.println("sessionId为"+session.getId()+"的WebSocket连接已经被迫关闭，关闭的原因是："+closeReason);
    }

    /**
     * 发送消息到指定的客户端
     * @param message 需要发送的消息
     * @param mapAcceptDataWebSocketClient 接收消息的webSocket客户端的Session集合
     */
    private void sendMessageToTargetClient(String message, Map<String, Session> mapAcceptDataWebSocketClient) {
        for (Map.Entry<String,Session> clientEntry : mapAcceptDataWebSocketClient.entrySet()) {
            Session client = clientEntry.getValue();
            client.getAsyncRemote().sendText(message);
        }
    }

    /**
     * 发送消息到所有的WebSocket客户端
     * @param message 需要发送的消息
     */
    private void sendMessageToAllClient(String message) {
        for (Map.Entry<String,Session> clientEntry : SessionUtils.clients.entrySet()) {
            Session client = clientEntry.getValue();
            client.getAsyncRemote().sendText(message);
        }
    }
}
